#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <poll.h>
#define PORT 12345
#define ClientNum 10
struct pollfd Poll_Client[ClientNum]; //定义 poll 结构体数组
/*******************************************************
 * Function name : Poll_Init
 * @Description  : 把 poll内的 fd描述符全部初始化为 -1
 * @MethodAuthor : gxl
 * Parameter     ：
 * Return        ：0 success  ,  other fail
 * @Date: 2021-11-11 16:07:01
 **********************************************************/
void Poll_Init(struct pollfd *pollfds)
{
    for (size_t i = 0; i < ClientNum; i++)
    {
        /* code */
        pollfds[i].fd = -1;     //把文件描述符全部初始化为-1
        pollfds[i].revents = 0; //返回时间初始为0
    }
}
int main(int argc, char const *argv[])
{
    int socket_fd, client_fd;
    int client_count = 0;
    socklen_t client_lenth = 0;
    int poll_ret;
    int socket_ret;
    int read_ret;
    int optval = 1;
    char readbuff[1024];
    struct sockaddr_in server_info;
    struct sockaddr_in client_info;
    /* 1 创建套接字 */
    socket_fd = socket(AF_INET, SOCK_STREAM, 0); // IPV4 TCP通信
    if (socket_fd == -1)
    {
        /* code */
        perror("socket\n");
        close(socket_fd);
        exit(-1);
    }
    /* 2 配置 允许端口复用  必须在bind绑定端口和地址之前使用*/
    socket_ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (int *)&optval, sizeof(int));
    if (socket_ret == -1)
    {
        /* code */
        perror("setsockopt\n");
        exit(EXIT_FAILURE);
    }
    /*3 绑定 端口号和地址 */
    memset(&server_info, 0, sizeof(struct sockaddr_in)); //清空结构体
    server_info.sin_family = AF_INET;
    server_info.sin_addr.s_addr = INADDR_ANY; //本地IP地址
    server_info.sin_port = htons(PORT);       //网络字节序转换
    socket_ret = bind(socket_fd, (struct sockaddr *)&server_info, sizeof(struct sockaddr_in));
    if (socket_ret == -1)
    {
        /* code */
        perror("bind\n");
        close(socket_fd);
        exit(-1);
    }
    /* 4 监听 客户端连接 */
    socket_ret = listen(socket_fd, ClientNum);
    if (socket_ret == -1)
    {
        /* code */
        perror("listen\n");
        close(socket_fd);
        exit(-1);
    }
    /* 初始化 poll  */
    Poll_Init(Poll_Client);
    Poll_Client[0].fd = socket_fd;  //添加描述符
    Poll_Client[0].events = POLLIN; //注册events事件
    while (1)
    {
        /* code */
        poll_ret = poll(Poll_Client, ClientNum, -1);
        if (poll_ret < 0)
        {
            /* code */
            perror("poll\n");
            continue; //结束本次循环
        }
        if (Poll_Client[0].fd == socket_fd && (Poll_Client[0].revents & POLLIN)) //触发socket_fd描述符感兴趣事件
        {
            /* code */
            memset(&client_info, 0, sizeof(struct sockaddr_in)); //清空结构体
            client_fd = accept(socket_fd, (struct sockaddr *)&client_info, &client_lenth);
            if (client_fd == -1)
            {
                /* code */
                perror("accept\n");
                close(client_fd);
                continue; //结束本次循环
            }
            for (size_t i = 0; i < ClientNum; i++)
            {
                /* code */
                if (Poll_Client[i].fd == -1)
                {
                    Poll_Client[i].fd = client_fd;  //把描述符添加到描述符集合
                    Poll_Client[i].events = POLLIN; //注册events事件
                    break;
                }
            }
            if (client_count > ClientNum)
            {
                /* code */
                printf("client connect num than Client Max limit\n");
                close(client_fd);
                continue; //结束本次循环
            }

            client_count++;
            printf("new client connect.....client_fd = %d\n", client_fd);
        }
        else
        {
            for (size_t i = 0; i < ClientNum; i++)
            {
                /* code */
                if (Poll_Client[i].fd == -1)
                    continue;                        //结束循环
                if (Poll_Client[i].revents & POLLIN) //非客户端连接，并且有感兴趣时间产生，读取数据
                {
                    /* code */
                    memset(readbuff, 0, sizeof(readbuff)); //清空缓冲区
                    read_ret = recv(Poll_Client[i].fd, readbuff, 1024, 0);
                    switch (read_ret)
                    {
                    case -1:
                        /* code */
                        printf("reciver data error\n");
                        break;
                    case 0: //客户端断开连接
                        printf("client %d close\n", Poll_Client[i].fd);
                        close(Poll_Client[i].fd);
                        break;
                    default:
                        printf("recive data form client %d\n", Poll_Client[i].fd);
                        printf("%s\n", readbuff);
                        break;
                    }
                }
            }
        }
    }
    return 0;
}
